#include "bsp_reader.h"

Bsp::Bsp()
{
}

Bsp::~Bsp()
{
}

void Bsp::read_header(std::ifstream& is)
{
	is.seekg(0, std::ios_base::beg);
	is.read(reinterpret_cast<char*>(&header__), sizeof(header__));
}
void Bsp::read_textures(std::ifstream& is)
{
	textures__.clear();
	is.seekg(header__.direntry[Bsp::TEXTURES].offset);
	int nb_textures = header__.direntry[Bsp::TEXTURES].length / sizeof(Bsp::texture_t);

	for (int i=0; i<nb_textures; i++)
	{
		Bsp::texture_t t;
		is.read(reinterpret_cast<char*>(&t), sizeof(t));
		textures__.push_back(t);
	}
}

void Bsp::read_models(std::ifstream& is)
{
	models__.clear();
	is.seekg(header__.direntry[Bsp::MODELS].offset);
	int nb_models = header__.direntry[Bsp::MODELS].length / sizeof(Bsp::model_t);

	for (int i=0; i<nb_models; i++)
	{
		Bsp::model_t m;
		is.read(reinterpret_cast<char*>(&m), sizeof(m));
		models__.push_back(m);
	}
}

void Bsp::read_faces(std::ifstream& is)
{
	faces__.clear();
	is.seekg(header__.direntry[Bsp::FACES].offset);
	int nb_faces = header__.direntry[Bsp::FACES].length / sizeof(Bsp::face_t);

	for (int i=0; i<nb_faces; i++)
	{
		Bsp::face_t f;
		is.read(reinterpret_cast<char*>(&f), sizeof(f));
		faces__.push_back(f);
	}
}

void Bsp::read_vertexes(std::ifstream& is)
{
	vertexes__.clear();
	is.seekg(header__.direntry[Bsp::VERTEXES].offset);
	int nb_vertexes = header__.direntry[Bsp::VERTEXES].length / sizeof(Bsp::vertex_t);

	for (int i=0; i<nb_vertexes; i++)
	{
		Bsp::vertex_t t;
		is.read(reinterpret_cast<char*>(&t), sizeof(t));
		vertexes__.push_back(t);
	}
}

bool Bsp::parse_str(std::stringstream& ss, std::string& s)
{
	bool done = false;
	char c;

	while (!done)
	{
		ss.read(&c, 1);
		if (ss.gcount() != 1)
		{
			done = true;
			continue;
		}
		if (c == '"')
			break;
		else
			s += c;
	}

	return done;
}

std::pair<bool, std::map<std::string, std::string> > Bsp::parse_acc(std::stringstream& ss)
{
	bool done = false;
	std::string s;
	std::string first;
	std::string second;
	char c;
	int counter = 0;
	std::map<std::string, std::string> m;

	while(!done)
	{
		ss.read(&c, 1);
		if (ss.gcount() != 1)
		{
			done = true;
			continue;
		}
		if (c == '}')
			break;
		if (c <= 32)
			continue;
		if (c == '"')
		{
			done = parse_str(ss, s);
			if (done)
				break;

			if (counter % 2 == 0)
				first = s;
			else
			{
				second = s;
				m[first] = second;
			}
			s = "";
			counter++;
		}
	}

	return std::pair<bool, std::map<std::string, std::string> >(done, m);
}


void Bsp::parse_entities(std::stringstream& ss)
{
	bool done = false;
	char c;

	while(!done)
	{
		ss.read(&c, 1);
		if (ss.gcount() != 1)
		{
			done = true;
			continue;
		}
		if (c <= 32)
			continue;
		if (c == '{')
		{
			std::pair<bool, std::map<std::string, std::string> > p;
			p = parse_acc(ss);

			if (p.first == true)
				break;
			entities__.push_back(p.second);
		}
	}
}

void Bsp::read_entities(std::ifstream& is)
{
	is.seekg(header__.direntry[Bsp::ENTITIES].offset);
	char* buffer = new char[header__.direntry[Bsp::ENTITIES].length +1];

	std::memset(buffer, 0, header__.direntry[Bsp::ENTITIES].length +1);
	
	is.read(buffer, header__.direntry[Bsp::ENTITIES].length);
	std::stringstream entities;
	entities << buffer;
	delete [] buffer;

	parse_entities(entities);
}

void Bsp::read_meshverts(std::ifstream& is)
{
	meshverts__.clear();
	is.seekg(header__.direntry[Bsp::MESHVERTS].offset);
	int nb_meshverts = header__.direntry[Bsp::MESHVERTS].length / sizeof(Bsp::meshvert_t);

	for (int i=0; i<nb_meshverts; i++)
	{
		Bsp::meshvert_t m;
		is.read(reinterpret_cast<char*>(&m), sizeof(m));
		meshverts__.push_back(m);
	}
}


void Bsp::load(const std::string& map)
{
	std::ifstream is(map.c_str(), std::ios::binary | std::ios::in);
	if (!is.is_open())
		throw Exception("Could not load file: " + map, __FILE__, __LINE__);

	read_header(is);
	read_textures(is);
	read_models(is);
	read_faces(is);
	read_vertexes(is);
	read_entities(is);
	read_meshverts(is);

	is.close();
}

std::vector<std::map<std::string, std::string> >& Bsp::entities()
{
	return entities__;
}

std::vector<Bsp::texture_t>& Bsp::textures()
{
	return textures__;
}

std::vector<Bsp::model_t>& Bsp::models()
{
	return models__;
}

std::vector<Bsp::face_t>& Bsp::faces()
{
	return faces__;
}

std::vector<Bsp::vertex_t>& Bsp::vertexes()
{
	return vertexes__;
}

std::vector<Bsp::meshvert_t>& Bsp::meshverts()
{
	return meshverts__;
}

